package com.app.client;

import com.app.game.chat.Message;
import com.app.game.other.Player;
import com.app.game.other.PlayerFix;
import com.app.head.Head;
import com.app.head.HeadsConst;
import com.app.head.impl.*;
import com.app.lan.Receiver;
import com.app.lan.Sender;
import com.app.observers.ClientObserver;
import com.app.observers.ServerObserver;
import com.app.observers.ServerSubject;
import com.app.task.Task;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ServerHandler extends Task implements ServerSubject, Serializable {

    private ObjectInputStream input;
    private ObjectOutputStream output;
    private Socket socket;
    ArrayList<ServerObserver> observers = new ArrayList<ServerObserver>();

    public ServerHandler(Socket socket) {
       this.socket = socket;
    }

    @Override
    protected void task() {
        try {
            
            Head head;
            if((head =(Head) input.readObject()) != null){
            int object = head.getObjectId();
            System.out.println(object);
            switch (object) {
                case HeadsConst.PLAYER:
                    playerDelivery((Player) head.getObject());
                    break;
                case HeadsConst.PLAYER_LIST:
                    playerListDelivery((HashMap<Integer, Player>) head.getObject());
                    break;
                case HeadsConst.GAME_STARTING:
                    gameStartDelivery();
                    break;
                case HeadsConst.GAME_ENDING:
                    gameOverDelivery();
                    break;
                case HeadsConst.RESULT:
                    roundResultDelivery((Integer) head.getObject());
                    break;
                case HeadsConst.READY_NOTIFICATION:
                    readyNotificationDelivery((Integer) head.getObject());
                    break;
                case HeadsConst.ROUND_DONE:
                    roundDoneNotification((Integer) head.getObject());
                    break;
                case HeadsConst.MESSAGE:
                    messageDelivery((Message)head.getObject());
                    break;
                case HeadsConst.PLAYER_UPDATE:
                    playerUpdateDelivery((PlayerFix)head.getObject());
                    break;
                case HeadsConst.PLAYER_LEFT: playerLeftDelivery((Integer)head.getObject());break;
            
            }
            }
            
        }catch(EOFException eof){
        	System.out.println(eof.getMessage());

        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
            closeConnection();
        }

    }
   
	private void playerLeftDelivery(Integer player){
    	for(ServerObserver ob: observers){
    		ob.updatePlayerLeft(player);
    	}
    }

    private void playerDelivery(Player player) {

        for (ServerObserver ob : observers) {
            ob.updatePlayer(player);
        }

    }

    private void playerListDelivery(HashMap<Integer, Player> players) {

        for (ServerObserver ob : observers) {
            ob.updatePlayers(players);
        }

    }

    private void roundResultDelivery(Integer result) {

        for (ServerObserver ob : observers) {
            ob.updateResult(result);
        }
    }

    private void messageDelivery(Message msg) {
        
        for (ServerObserver ob : observers) {
            ob.updateMessage(msg);
        }


    }

    private synchronized void gameStartDelivery() {

        for (ServerObserver ob : observers) {
            ob.updateGameStarting();
        }

    }

    private void gameOverDelivery() {
        for (ServerObserver ob : observers) {
            ob.updateGameOver();
        }
        closeConnection();
    }

    private void readyNotificationDelivery(Integer player) {

        for (ServerObserver ob : observers) {
            ob.updateReadyNotification(player);
        }


    }
    public void sendUpdatedPlayer(PlayerFix player){
        HeadUpdatedPlayer hup = new HeadUpdatedPlayer();
        hup.setObject(player);
        try {
            output.writeObject(hup);
        } catch (IOException ex) {
            Logger.getLogger(ServerHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    public void sendPlayer(Player player) {
        while(output==null){
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                Logger.getLogger(ServerHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        HeadPlayer headPlayer = new HeadPlayer();
        headPlayer.setObject(player);
        //headSender.setObject(headPlayer);
        //playerSender.setObject(player);
        try {
            output.writeObject(headPlayer);
            //playerSender.send();
        } catch (IOException e) {
        }
    }

    public void sendRoundDone() {
        HeadRoundDone headRoundDone = new HeadRoundDone();
        //headRoundDone.setObject(true);
        //headSender.setObject(headRoundDone);
        try {
            output.writeObject(headRoundDone);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendReady() {
        HeadReady headReady = new HeadReady();
        headReady.setObject(true);
        //headSender.setObject(headReady);
        try {
            output.writeObject(headReady);
        } catch (IOException e) {

            e.printStackTrace();
        }
    }

    public void sendMessage(Message msg) {
        Head headMsg = new HeadMessage();
        headMsg.setObject(msg);

        //headSender.setObject(headMsg);
        //msgSender.setObject(msg);
        try {
            output.writeObject(headMsg);
            //headSender.send();
            //msgSender.send();
        } catch (IOException e) {

            e.printStackTrace();
        }
    }
    
    public void sendPlayerLeft(Integer id){
    	HeadPlayerLeft head = new HeadPlayerLeft();
    	head.setObject(id);
    	try {
			output.writeObject(head);
		} catch (IOException e) {
			
			e.printStackTrace();
		}
    	closeConnection();
    }

    @Override
    public void registerObserver(ServerObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(ServerObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void beforeTask() {
         try {
            input = new ObjectInputStream(socket.getInputStream());
            output = new ObjectOutputStream(socket.getOutputStream());

            
        } catch (IOException e) {

            e.printStackTrace();
        }
    }

    private void roundDoneNotification(Integer integer) {
        for(ServerObserver ob: observers){
            ob.updateReadyNotification(integer);
        }
    }

    private void playerUpdateDelivery(PlayerFix player) {
        for(ServerObserver ob: observers){
            
        	ob.reUpdatePlayer(player);
        }
    }
    
    private void closeConnection(){
    	stop();
    	try{
    		input.close();
    		output.close();
    		socket.close();
    	}catch(IOException e){
    		e.printStackTrace();
    	}
    	}
    
}
